<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>设计模式</title>
	</head>
	<body>
		<!-- https://rapidsu.cn/articles/3072 -->
		<script>
			function doDivide() {
				// console.log('==================================================')
				console.log('\n\n')
			}

			{
				// 工厂模式
				// 工厂方法模式定义了一个创建对象的接口，但是由子类决定要实例化的类是哪一个。可以将对象的创建和使用分离，使得系统更加灵活
				class Animal {
					speak() {
						throw new Error('This method must be implemented.');
					}
				}
				// 实现具体的类
				class Dog extends Animal {
					speak() {
						return 'Woof!';
					}
				}
				class Cat extends Animal {
					speak() {
						return 'Meow!';
					}
				}
				// 实现工厂方法
				class AnimalFactory {
					createAnimal(animalType) {
						switch (animalType) {
							case 'dog':
								return new Dog();
							case 'cat':
								return new Cat();
							default:
								throw new Error(`Invalid animal type: ${animalType}`);
						}
					}
				}
				// 使用工厂方法创建对象
				const animalFactory = new AnimalFactory();
				const dog = animalFactory.createAnimal('dog');
				console.log(dog.speak()); // Output: Woof!
				const cat = animalFactory.createAnimal('cat');
				console.log(cat.speak()); // Output: Meow!
				doDivide()
			}

			{
				// 单例模式
				// 单例模式的目的是确保一个类只有一个实例，并为该实例提供全局访问点
				class Logger {
					constructor() {
						if (!Logger.instance) {
							this.logs = [];
							Logger.instance = this;
						}
						return Logger.instance;
					}
					log(message) {
						this.logs.push(message);
						console.log(`Logger: ${message}`);
					}
					printLogCount() {
						console.log(`Number of logs: ${this.logs.length}`);
					}
				}
				// 可以使用全局变量来访问实例
				const logger = new Logger();
				Object.freeze(logger);
				// 对于每个实例，输出应该是相同的
				logger.log('First message'); // Output: Logger: First message
				logger.printLogCount(); // Output: Number of logs: 1
				const anotherLogger = new Logger(); // 此时返回一个已经存在的实例
				anotherLogger.log('Second message'); // Output: Logger: Second message
				anotherLogger.printLogCount(); // Output: Number of logs: 2
				doDivide()
			}

			{
				// 原型模式
				// 原型模式（Prototype Pattern）是一种创建型设计模式，它可以用于创建对象的成本相对较高，但对于由相同属性的对象可以通过克隆来创建。原型模式将对象的创建过程和对象的使用过程分离，它通过克隆已有对象来创建新的对象，从而避免了昂贵的对象创建过程。在 JavaScript 中，原型模式的实现很容易，因为它天然支持对象的 clone（即浅拷贝）
				// 创建一个原型对象
				const carPrototype = {
					wheels: 4,
					color: 'red',
					start() {
						console.log('Starting the car...');
					},
					stop() {
						console.log('Stopping the car...');
					},
				};
				// 使用Object.create()方法克隆
				const car1 = Object.create(carPrototype);
				console.log(car1); // Output: {}
				car1.wheels = 6;
				console.log(car1.wheels); // Output: 6
				console.log(car1.color); // Output: red
				car1.start(); // Output: Starting the car...
				car1.stop(); // Output: Stopping the car...
				// 克隆另一个对象
				const car2 = Object.create(carPrototype);
				console.log(car2); // Output: {}
				car2.color = 'blue';
				console.log(car2.color); // Output: blue
				console.log(car2.wheels); // Output: 4
				car2.start(); // Output: Starting the car...
				car2.stop(); // Output: Stopping the car...
				doDivide()
			}

			{
				// 代理模式
				// 代理模式（Proxy Pattern）是一种结构型设计模式，它允许在访问对象时提供一个占位符或代理，以控制对对象的访问
				// 主题接口
				class Subject {
					request() {
						console.log('Subject：处理请求');
					}
				}
				// 真实主题类
				class RealSubject extends Subject {
					request() {
						console.log('RealSubject：处理请求');
					}
				}
				// 代理类
				class Proxy extends Subject {
					constructor(realSubject) {
						super();
						this.realSubject = realSubject;
					}
					request() {
						if (this.checkAccess()) {
							this.realSubject.request();
							this.logAccess();
						}
					}
					checkAccess() {
						console.log('Proxy：检查访问权限');
						return true;
					}
					logAccess() {
						console.log('Proxy：记录访问日志');
					}
				}
				// 使用代理访问真实对象
				const realSubject = new RealSubject();
				const proxy = new Proxy(realSubject);
				proxy.request();
				doDivide()
			}

			{
				// 组合模式
				// 组合模式（Composite Pattern）是一种结构型设计模式，它使用树形结构来表示对象的部分-整体层次结构，并使用户能够以统一的方式处理单个对象和对象组合
				// 抽象构件
				class Component {
					constructor(name) {
						this.name = name;
					}
					operation() {
						console.log(`Component ${this.name}：执行操作`);
					}
					add(component) {
						console.log('Component：不支持的操作');
					}
					remove(component) {
						console.log('Component：不支持的操作');
					}
					getChild(index) {
						console.log('Component：不支持的操作');
					}
				}
				// 叶子节点
				class Leaf extends Component {
					constructor(name) {
						super(name);
					}
				}
				// 树枝节点
				class Composite extends Component {
					constructor(name) {
						super(name);
						this.children = [];
					}
					add(component) {
						this.children.push(component);
					}
					remove(component) {
						const index = this.children.indexOf(component);
						if (index >= 0) {
							this.children.splice(index, 1);
						}
					}
					getChild(index) {
						return this.children[index];
					}
				}
				// 使用组合模式
				const root = new Composite('根');
				const branch1 = new Composite('树枝1');
				const branch2 = new Composite('树枝2');
				const leaf1 = new Leaf('叶子1');
				const leaf2 = new Leaf('叶子2');
				const leaf3 = new Leaf('叶子3');
				root.add(branch1);
				root.add(branch2);
				branch1.add(leaf1);
				branch1.add(leaf2);
				branch2.add(leaf3);
				root.operation(); // Output: Component 根：执行操作
				branch1.operation(); // Output: Component 树枝1：执行操作
				branch1.remove(leaf2);
				branch2.operation(); // Output: Component 树枝2：执行操作
				root.getChild(0).operation(); // Output: Component 树枝1：执行操作
				doDivide()
			}

			{
				// 策略模式
				// 策略模式是一种设计模式，它定义了一系列算法，并将每个算法封装起来，使它们可以相互替换。策略模式让算法独立于使用它的客户端而独立变化。这种模式属于行为型模式
				class Strategy {
					constructor(name) {
						this.name = name;
					}
					execute() {}
				}
				class StrategyA extends Strategy {
					execute() {
						console.log('Executing strategy A');
					}
				}
				class StrategyB extends Strategy {
					execute() {
						console.log('Executing strategy B');
					}
				}
				class Context {
					constructor(strategy) {
						this.strategy = strategy;
					}
					executeStrategy() {
						this.strategy.execute();
					}
				}
				let context = new Context(new StrategyA('A'));
				context.executeStrategy(); // Executing strategy A
				context.strategy = new StrategyB('B');
				context.executeStrategy(); // Executing strategy B
				doDivide()
			}

			{
				// 观察者模式
				// 观察者模式是一种行为设计模式，其中对象之间存在一对多的依赖关系。当一个对象的状态发生变化时，它的所有依赖者都得到通知并自动更新。观察者模式将对象之间的关系解耦，使得它们可以独立变化
				class Subject {
					constructor() {
						this.observers = [];
					}
					attach(observer) {
						this.observers.push(observer);
					}
					detach(observer) {
						const index = this.observers.indexOf(observer);
						if (index > -1) {
							this.observers.splice(index, 1);
						}
					}
					notify() {
						for (const observer of this.observers) {
							observer.update(this);
						}
					}
				}
				class Observer {
					update(subject) {}
				}
				class ConcreteSubject extends Subject {
					constructor(state) {
						super();
						this.state = state;
					}
					set_state(state) {
						this.state = state;
						this.notify();
					}
					get_state() {
						return this.state;
					}
				}
				class ConcreteObserver extends Observer {
					update(subject) {
						console.log(`Got updated value: ${subject.get_state()}`);
					}
				}
				let subject = new ConcreteSubject('initial state');
				let observer = new ConcreteObserver();
				subject.attach(observer);
				subject.set_state('new state');
				doDivide()
			}
		</script>
	</body>
</html>